<template>
 <div id="edit" class="edit">
     <el-row :type="'flex'">
         <el-col :xs="4" :lg="4" :xl="4" :span="4">
             <div class="grid-content eles">
                 <div class='electn'>
                   <transition name="rotateDownLeft">
                     <div class="els" v-for="(v, k) in els" :key="k">
                       <span class="els-title" v-text="v.title"></span>
                       <div class="els-items" onselectstart="return false;">
                         <div onselectstart="return false;" class="els-it" v-for="(vi, ki) in v.els" :tabindex="ki + 10" :key="ki" @click.stop="product(vi.value)" @keyup="product(vi.value, $event)" v-labeldrag="vi.value">
                           <i :class="vi.icon"></i>
                           <span v-text="vi.txt" onselectstart="return false;"></span>
                         </div>
                       </div>
                     </div>
                   </transition>
                 </div>
             </div>
         </el-col>
         <el-col :xs="14" :lg="14" :xl="14" :span="14">
             <div ref="editctn" class="grid-content editctn" id="editctn">
               <draggable v-model="vNodes" :options="{group:'elements'}" @start="drag=true" @end="drag=false" @change="updateIndex">
                 <transition-group name="bounce" enter-active-class="bounceInDown" leave-active-class="bounceOutLeft">
                   <div ref="combox" class="combox" v-for="(v, k) in vNodes" :key="k" :style="{width: (1/v.mine.cols * 100) + '%', opacity: v.mine.hidden ? '0.3' : '1'}" @click.stop="setIndex(k)">
                     <div style="width: 100%;">
                       <div v-if="v.mine" class="edit-discribe">
                         <span v-text="v.mine.describe"></span>
                         <i v-if="v.mine.isneed" class="edit-need">*</i>
                         <span v-if="v.mine.readonly">(只读)</span>
                       </div>
                      <template v-if="v.mine || v.attrs">
                        <component :is="v.elname" v-bind.sync="v.attrs" v-model="v.model" :style="{float: v.mine.align}">
                          <span v-if="v.mine.text" v-text="v.mine.text"></span>
                          <component v-for="(vi, ki) in v.items" :key="ki" v-bind="vi.attrs" :is="vi.elname">
                            <span v-if="v.list">{{ (typeof v.list[ki] === 'object' ? v.list[ki].label : v.list[ki]) }}</span>
                          </component>
                        </component>
                      </template>
                     </div>
                     <i class="del el-icon-delete" @click.stop="remove(k)"></i>
                   </div>
                 </transition-group>
               </draggable>
             </div>
         </el-col>
         <el-col :xs="6" :lg="6" :xl="6" :span="6">
             <div class="grid-content props">
               <template v-if="vNodes.length">
                 <template v-if="vNodes[index].mine || vNodes[index].attrs">
                   <draggable v-model="elProps" :options="{group:'props'}" @start="drag=true" @end="drag=false">
                    <transition-group name="rotateDownRight">
                      <!-- <keep-alive> -->
                        <div class="propsbox" v-for="(v, k) in elProps" :key="k">
                          <span class="lab" v-text="v.label"></span>
                          <template v-if="v.isAttrs">
                            <template v-if="v.type">
                              <component :is="v.struct" :type="v.type" v-model="vNodes[index]['attrs'][v.model]" v-bind="v.attrs">
                              <template v-if="v.childStruct">
                                <component :is="v.childStruct" v-for="(vi, ki) in v.items" :key="ki" v-bind="vi"></component>
                              </template>
                              </component>
                            </template>
                            <template v-else>
                              <component :is="v.struct" v-model="vNodes[index]['attrs'][v.model]" v-bind="v.attrs">
                              <template v-if="v.childStruct">
                                <component :is="v.childStruct" v-for="(vi, ki) in v.items" :key="ki" v-bind="vi"></component>
                              </template>
                              </component>
                            </template>
                          </template>
                          <template v-else>
                            <template v-if="vNodes[index]['mine']">
                              <template v-if="vNodes[index]['mine'][v.model] || vNodes[index]['mine'][v.model] >= 0">
                                <component @change="selectCom($event, v.for)" @blur="getItems(vNodes[index]['mine'].dataUrl)" :is="v.struct" v-model="vNodes[index]['mine'][v.model]" filterable>
                                  <template v-if="v.hasDefData">
                                    <component :is="v.childStruct" v-for="(vi, ki) in v.defData" :key="ki" v-bind="vi"></component>
                                  </template>
                                  <template v-else>
                                    <component :is="v.childStruct" v-for="(vi, ki) in comsbus" :key="ki" v-bind="vi"></component>
                                  </template>
                                </component>
                              </template>
                            </template>
                            <template v-if="vNodes[index][v.model]">
                              <component :is="v.struct" v-bind.sync="vNodes[index]" v-model="vNodes[index][v.model][0]['label']" :comItem="comItem" :clear="clear"></component>
                            </template>
                            <template v-if="v.noModel">
                              <component :is="v.struct" v-bind.sync="vNodes[index]"></component>
                            </template>
                          </template>
                        </div>
                      <!-- </keep-alive> -->
                    </transition-group>
                   </draggable>
                 </template>
               </template>
             </div>
         </el-col>
     </el-row>
     <nonce :nodelist="vNodes" :formid="formid"></nonce>
 </div>
</template>

<script>
import { allocate, getEls } from '@/config/ele.config'
import draggable from 'vuedraggable'
import { propsConfig } from '@/config/props.config'
import mutiple from './mutiple'
import _S from '@/config/s'
import cascadeLabel from './cascade-label'
import dsCom from 'com/dsCom/dstext'
import { INDEXCOM } from '@/store/types'
import nonce from '../nonce'
export default {
  data () {
    return {
      loading: false,
      vNodes: [],
      els: [],
      index: null,
      elProps: null,
      clear: '',
      comItem: []
    }
  },
  watch: {
    index (newIndex) {
      console.log(newIndex)
      if (this.index != void +0 && this.vNodes[this.index].mine.dataUrl && this.vNodes[this.index].mine.dataUrl.length >>> 0 > 0) {
        this.vNodes[this.index]._url = this.vNodes[this.index]._url === void +0 ? 0 : this.vNodes[this.index]._url
        this.vNodes[this.index]._field = this.vNodes[this.index]._field === void +0 ? 0 : this.vNodes[this.index]._field
      }
      this.$nextTick(() => {
        if (newIndex == void +0) this.elProps = []
        if (!isNaN(parseInt(newIndex))) {
          if (this.vNodes[this.index]) this.elProps = propsConfig(this.vNodes[newIndex].elname)
          this.$store.dispatch(INDEXCOM, this.vNodes[this.index])
          this.$forceUpdate()
        }
      })
      if (!isNaN(parseInt(newIndex))) {
        if (!this.vNodes[this.index]._field) {
          this.$watch(() => {
            if (this.index == void +0) return //  这里是一个隐式转换，请勿改强等, 若改，请重启eslint(eqeqeq)规则
            return this.vNodes[this.index].mine.value
          }, (nv) => {
            if (!nv) return
            for (let v of this.comsbus) {
              if (v.value === nv) {
                this.vNodes[this.index].mine.describe = v.label
              } else continue
            }
          }, {
            immediate: true
          })
          this.vNodes[this.index]._field++
        }
      }
    },
    config (nv) {
      this.index = null
      this.vNodes = []
      this.parseComps()
    }
  },
  methods: {
    //  生成元素的函数
    product (elname, keyup) {
      if (keyup) {
        keyup = keyup.keyCode || keyup.which
        if (keyup !== 13) {
          return
        }
      }
      let obj = Object.create(null)
      if (elname === 'ds-text') {
        obj = allocate({
          elname: elname,
          mine: {
            readonly: true
          }
        })
      } else obj = allocate(elname)
      if (typeof elname === 'object') {
        let config = elname
        obj = allocate(config)
      }
      obj['formid'] = this.formid
      this.vNodes.push(obj)
      this.index = this.vNodes.length - 1
      this.elProps = propsConfig(this.vNodes[this.index].elname)
    },
    //  移除元素的函数
    remove (k) {
      this.$nextTick(() => {
        if (this.vNodes.length === 1) {
          this.vNodes = []
          this.index = null
          return
        }
        let _k = k === this.vNodes.length - 1 ? k - 1 : k
        this.vNodes.splice(k, 1)
        this.index = _k
        if (this.vNodes[this.index]) this.elProps = propsConfig(this.vNodes[this.index].elname)
      })
    },
    //  字段选择下拉框change时的事件处理
    selectCom (comVal, vfor) {
      if (vfor === 'value') {
        for (let i in this.vNodes[this.index].items) {
          this.vNodes[this.index].items[i].mine.business = ''
          this.vNodes[this.index].items[i].mine.value = ''
          this.$forceUpdate()
        }
        this.clear = false
        let formBusiness = this.$store.state.indexPath.indexTap.business
        this.vNodes[this.index].mine.business = `${formBusiness}-${comVal}`
        this.$store.dispatch(INDEXCOM, this.vNodes[this.index])
        this.$nextTick().then(() => {
          this.comItem = this.comsbus.filter(v => v.value === comVal)[0].children
          this.$forceUpdate()
        })
      }
    },
    //  设置当前元素的索引
    setIndex (k) {
      this.index = k
      if (this.vNodes[this.index]) this.elProps = propsConfig(this.vNodes[this.index].elname)
    },
    //  跟新当前元素的索引
    updateIndex ({moved}) {
      this.index = moved.newIndex
      if (this.vNodes[this.index]) this.elProps = propsConfig(this.vNodes[this.index].elname)
    },
    //  根据dataUrl获取元素的子项
    getItems (dataUrl) {
      if (!dataUrl) return
      if (!this.vNodes[this.index]._url) {
        if (!this.vNodes[this.index]) return
        this.$watch(() => {
          if (this.index == void +0) return //  这里是一个隐式转换，请勿改强等, eslint中此规则被我关闭
          return this.vNodes[this.index].mine.dataUrl
        },
        async (nv, ov) => {
          if (nv === void +0) return
          let arrurl = nv.split('/')
          if (!/^(http|https)/.test(arrurl[0])) return
          if (!/(192.168.21.145)/g.test(arrurl[2])) return
          if (!/(?=rest\/org\/codeList\/common_list\/)/.test(arrurl.splice(3, arrurl.length - 1).join('/'))) return
          this.$axios({url: nv, timeout: 1500}).then(({data}) => {
            this.vNodes[this.index].model = ''
            this.vNodes[this.index].list = []
            const len = this.vNodes[this.index].items.length >>> 0
            if (data.length <= len) this.vNodes[this.index].items = this.vNodes[this.index].items.slice(0, data.length)
            for (let [k, v] of data.entries()) {
              let o = Object.create(null)
              o = {
                label: v.value,
                value: v.key
              }
              this.vNodes[this.index].list.push(o)
              if (k < len) {
                this.vNodes[this.index].items[k].attrs.label = v.value
                this.vNodes[this.index].items[k].attrs.value = v.key
              } else {
                let _o = JSON.parse(JSON.stringify(this.vNodes[this.index].items[1]))
                _o.attrs.label = o.label
                _o.attrs.value = o.value
                this.vNodes[this.index].items.push(_o)
              }
            }
            this.$forceUpdate()
          }).catch(reject => {
            console.error(reject)
            return this.$notify.error('请求失败，请确认dataUrl合法性！！！')
          })
        }, {
          immediate: true
        })
        this.vNodes[this.index]._url++
      }
    },
    //  将后端的数据转换设计器可渲染的数据并进行渲染(读取表单)
    parseComps () {
      if (!this.config || !(this.config.length >>> 0)) return
      this.$store.dispatch('fetchComps', {
        desCode: this.config,
        userToken: 'admin'
      }).then(({data}) => {
        let attrs = data.attributes
        for (let v of attrs) {
          let o = {
            elname: v.showType,
            mine: {
              align: v.align,
              cols: v.cols,
              rows: v.rows,
              dataUrl: v.dataUrl,
              hidden: v.hidden,
              describe: v.name,
              readonly: v.readonly,
              isneed: v.isneed,
              idField: v.idField,
              showType: v.showType,
              value: v.attrName
            }
          }
          this.product(o)
        }
      })
    }
  },
  async created () {
    this.$nextTick(() => {
      //  获取左侧元素面板所有元素
      this.els = [...getEls()]
      //  如果存在子项的元素子项全空时，跟新这个元素，将其移除
      _S.$on('noitems', () => {
        this.vNodes.splice(this.index, 1)
        this.vNodes.length === 0 ? this.index = null : (this.index === 0 ? this.$forceUpdate() : this.index -= 1)
        parseInt(this.index) >= 0 ? this.elProps = propsConfig(this.vNodes[this.index].elname) : this.elProps = []
        this.$forceUpdate()
      })
      //  存在一个跟新右侧属性面板的事件
      _S.$on('updateProps', () => {
        parseInt(this.index) >= 0 ? this.elProps = propsConfig(this.vNodes[this.index].elname) : this.elProps = []
        this.$forceUpdate()
      })
      //  清空选中元素的已选字段,重置表单时会触发此事件
      _S.$on('updateComs', () => {
        if (this.vNodes.length > 0 && this.vNodes[this.index].mine) {
          for (let i in this.vNodes) {
            if (this.vNodes[i].formid !== this.indexTap) return
            this.vNodes[i].mine.value = ''
            this.vNodes[i].mine.business = ''
            for (let k in this.vNodes[i].items) {
              this.$nextTick(() => {
                this.vNodes[i].items[k].mine.value = ''
                this.vNodes[i].items[k].mine.business = ''
                this.clear = true
                this.$forceUpdate()
              })
            }
          }
          this.$store.dispatch(INDEXCOM, this.vNodes[this.index])
        }
      })
    })
  },
  mounted () {
    this.parseComps()
  },
  computed: {
    formid () {
      let _tap = this.$store.state.indexPath.indexTap.name
      return _tap
    },
    comsbus () {
      return this.formCom
    }
  },
  components: {
    draggable,
    mutiple,
    cascadeLabel,
    nonce,
    'ds-text': dsCom
  },
  props: {
    indexTap: {
      type: String
    },
    formCom: {
      type: Array
    },
    config: {
      type: String
    }
  }
}
</script>
<style lang="stylus">
.combox
    flex: 1
    min-height: 6rem
    display: flex
    padding-left: 14px
    padding-right: 3.5rem
    align-items: center
    overflow-x: hidden
    cursor: pointer
    box-sizing: border-box
    margin-left: 4px
    background-color: #deeade
    border-bottom: 1px solid #0ac
    z-index: 1
    position: relative
    .edit-discribe
      display: flex
      align-items: center
      font-size: 1rem
      min-height: 1rem
      margin-top: 1.5%
      .edit-need
        display: inline-block
        height: 1.2rem
        line-height: 1.5
        color: #f22
    .el-upload-dragger
      display: flex
      align-items: center
      justify-content: center
    &:hover
      box-shadow -4px 0 0 0 #0ac
      border-bottom: 1px solid #0ac
      background-color: rgba(110, 214, 224, 0.5) !important
      transform: translate(0, -6px)
      box-shadow: 0px 4px 10px 2px #aaa
      border-radio: 4px
    &:last-child
      border-bottom: none
      border-color: transparent
      border: none
    .del
      position: absolute
      display: flex
      justify-content: center
      align-items: center
      right: 1.2%
      top: 0
      bottom: 0
      margin: auto
      width: 2rem
      height: 2rem
      color: #f22
      background-color: rgb(235, 235, 235)
      border-radius: 2rem
      cursor: pointer
      &:hover
        background-color: #fff
        color: #f00
        box-shadow: 0 0 4px 2px #5ad
#edit
  display: flex
  width: 100%
  height: calc(100vh - 45px)
  box-sizing: border-box
  .el-row
    width: 100%
    & > .el-col-6
      overflow-y: scroll
      padding-bottom: 2.4rem
  .grid-content
    overflow: auto
  .eles
    display: flex
    flex-wrap: wrap
    flex-direction: columns
    font-size: 0.9rem
    .elinput
      max-height: 3rem
      .el-input__inner
        color: #222
        border-radius: 0
        border: none
        border-bottom: 1px dashed #222
        letter-spacing: 1px
        font-size: 1.2rem
        font-weight: 700
    .electn
      box-sizing: border-box
      width: 100%
      padding: 0 15px
      flex: 1
      .product
        width: 80%
    .els-title
      color: #888
      width: 100%
      display: flex
      height: 2rem
      align-items: center
    .els-items
      display: flex
      flex-wrap: wrap
      align-items: center
      justify-content: space-between
      user-select: none
      .els-it
        width: 50%
        user-select: none
        height: 1.8rem
        display: flex
        justify-content: center
        align-items: center
        font-size: 0.8rem
        cursor: move
        box-sizing: border-box
        margin-top: 5px
        &:hover, &:active, &:focus
          border: 1px dashed #77BDFF
          color: #0DB3A6
          transform: translate(0, -2.5px)
        span
          cursor: pointer
  .props
    .propsbox
      cursor: move
      flex: 1
      display: flex
      align-items: center
      justify-content: space-between
      overflow-x: hidden
      flex-direction: column
      min-height: 2.4rem
      margin-top: .5rem
      padding: .5rem .2rem
      flex-wrap: wrap
      box-sizing: border-box
      &:hover
        transform: translate(0, -4px)
        box-shadow: 0px 0px 30px 4px #aaa
      .lab
       display: flex
       width: 100%
       justify-content: flex-start
       font-size: .8rem
       overflow: hidden
       color: #0ac
       margin-bottom: .3rem
       box-sizing: border-box
  .editctn
    box-sizing: border-box
    width: 100%
    height: 100%
    padding-bottom: 2.4rem
</style>
